/******************************************************************************************
Copyright(C), 2019-2020, Linyar.
文件名：L_MPP40_vpss.c
作者：燕卫博	版本：V1.1	创建日期：2021.5.27
文件描述：
    对Hi3516DV300平台执行MPP-VPSS初始化。
版本信息：
    9Hv2，个人。
历史修改记录：
1. 2021-5-27:V1.1 燕卫博
从STv9-t拷贝更改。

2. 2021-8-11:V1.0 燕卫博
从9Hv1拷贝，接续使用。
******************************************************************************************/
//                                              ↓
//+------------------------------------------------------------------------------------------+
//|                                          文件说明
//+------------------------------------------------------------------------------------------+
//|      VPSS分组接收数据，提供用户对组的管理。Hi3516CV500/Hi3516AV300/Hi3516DV300/Hi3556V200
//|  /Hi3559V200最大支持16个GROUP。——《参考》P776
//|      当Hi3519AV100/Hi3516CV500/Hi3516DV300/Hi3556V200/Hi3559V200/Hi3516EV200 VPSS的GROUP0
//|  工作在VI_ONLINE_VPSS_ONLINE模式时，只有GROUP0可以被创建。——《参考》P701
//|      Hi3516CV500/Hi3516AV300/Hi3516DV300/Hi3556V200/Hi3559V200/Hi3516EV200的VPSS支持的最
//|  大物理通道数目为3。——《参考》P778
//|  VPSS设置流程为：
//|    第一步：设置组的属性并创建组。
//|    第二步：设置通道的属性，设置时将其绑定在一个组上。
//|    第三步：启动这个组的已设置的通道。
//|    第四步：启动这个组。
//|    第五步：执行组和数据来源的绑定。
//|      在本工程中，只涉及一路视频的采集，VI-VPSS工作在“双在线”模式下。本程序中启用了VPSS的
//|  GROUP0中的2个通道(Chn0, Chn1)。Chn0输出原始分辨率的图像，Chn1输出缩小后的图像。除缩放外
//|  不对图像做其它操作。
//+------------------------------------------------------------------------------------------+
//|  编写参考《HiMPP V4.0媒体处理软件开发参考(2019-8-1)》（简称《参考》）。
//+------------------------------------------------------------------------------------------+
//|                                         头文件包含
//+------------------------------------------------------------------------------------------+
/*|*/  #include "L_MPP40_vpss.h"
/*|*/  #include "L_MPP40_debug.h"
//+------------------------------------------------------------------------------------------+
//|                                         参数宏定义
//+------------------------------------------------------------------------------------------+
/*|*/  #define SENSOR_WIDTH  1920
/*|*/  #define SENSOR_HEIGHT 1080
//+------------------------------------------------------------------------------------------+
//|                                          函数声明
//+------------------------------------------------------------------------------------------+
/*|*/int  L_VIbindVPSS(VI_PIPE ViPipe, VI_CHN ViChn, VPSS_GRP VpssGrp);
/*|*/void L_VIunbindVPSS(VI_PIPE ViPipe, VI_CHN ViChn, VPSS_GRP VpssGrp);
//+------------------------------------------------------------------------------------------+
//|                                          全局变量
//+------------------------------------------------------------------------------------------+
/*|*/  VPSS_PARA_S stVPSSpara;
//|
/*|*/  static const VPSS_PARA_S stVPSSpara_default=
/*|*/  {
/*|*/      .stVPSSGroup_para=
/*|*/      {
/*|*/          .VpssGrp=0,
/*|*/          .stVpssGrpAttr=
/*|*/          {
/*|*/              .enDynamicRange             =DYNAMIC_RANGE_SDR8,
/*|*/              .enPixelFormat              =PIXEL_FORMAT_YVU_SEMIPLANAR_420,
/*|*/              .u32MaxW                    =SENSOR_WIDTH,
/*|*/              .u32MaxH                    =SENSOR_HEIGHT,
/*|*/              .bNrEn                      =HI_TRUE,
/*|*/              .stNrAttr.enNrType          =VPSS_NR_TYPE_VIDEO,
/*|*/              .stNrAttr.enNrMotionMode    =NR_MOTION_MODE_NORMAL,
/*|*/              .stNrAttr.enCompressMode    =COMPRESS_MODE_FRAME,
/*|*/              .stFrameRate.s32SrcFrameRate=-1,
/*|*/              .stFrameRate.s32DstFrameRate=-1,
/*|*/          }
/*|*/      },
/*|*/      .stVPSSChn1_para=
/*|*/      {
/*|*/          .VpssChn=1,
/*|*/          .stVpssChnAttr=
/*|*/          {
/*|*/              .u32Width                  =320,
/*|*/              .u32Height                 =180,
/*|*/              .enChnMode                 =VPSS_CHN_MODE_USER,
/*|*/              .enCompressMode            =COMPRESS_MODE_NONE,
/*|*/              .enDynamicRange            =DYNAMIC_RANGE_SDR8,
/*|*/              .enPixelFormat             =PIXEL_FORMAT_YUV_SEMIPLANAR_420,
/*|*/              .stFrameRate.s32SrcFrameRate=30,
/*|*/              .stFrameRate.s32DstFrameRate=30,
/*|*/              .u32Depth                  =2,
/*|*/              .bMirror                   =HI_FALSE,
/*|*/              .bFlip                     =HI_FALSE,
/*|*/              .enVideoFormat             =VIDEO_FORMAT_LINEAR,
/*|*/              .stAspectRatio.enMode      =ASPECT_RATIO_NONE,
/*|*/          }
/*|*/      },
/*|*/      .stVPSSChn2_para=
/*|*/      {
/*|*/          .VpssChn=2,
/*|*/          .stVpssChnAttr=
/*|*/          {
/*|*/              .u32Width                  =1920,
/*|*/              .u32Height                 =1080,
//|                ----------------------------------------
//|                只有工作在离线模式下，通道才支持AUTO模式。
//|                通道设置为AUTO模式时，只能与一个接收者绑定。
//|                通道设置为AUTO模式时，Hi3559AV100ES只支持
//|                与VO模块绑定，Hi3559AV100/Hi3519AV100支持
//|                与VO、VENC或PCIV模块绑定。AUTO模式绑定
//|                VENC时，不支持放大。
//|                ——《参考》P795
//|                ----------------------------------------
/*|*/              .enChnMode                 =VPSS_CHN_MODE_USER,
/*|*/              .enCompressMode            =COMPRESS_MODE_NONE,
/*|*/              .enDynamicRange            =DYNAMIC_RANGE_SDR8,
/*|*/              .enPixelFormat             =PIXEL_FORMAT_YVU_SEMIPLANAR_420,
/*|*/              .stFrameRate.s32SrcFrameRate=30,
/*|*/              .stFrameRate.s32DstFrameRate=30,
/*|*/              .u32Depth                  =2,
/*|*/              .bMirror                   =HI_FALSE,
/*|*/              .bFlip                     =HI_FALSE,
/*|*/              .enVideoFormat             =VIDEO_FORMAT_LINEAR,
/*|*/              .stAspectRatio.enMode      =ASPECT_RATIO_NONE,
/*|*/          }
/*|*/      },
/*|*/  };
//+------------------------------------------------------------------------------------------+

//+------------------------------------------------------------------------------------------+
//|  函数名称：L_VPSS_Init
//|  功能描述：在MPP4.0上进行视频编码所需的VPSS初始化。
//|  参数说明：无
//|  返回值说明：成功返回0
//|  备注：本函数执行的是VPSS中GROUP、CHN的设置、创建、使能以及VI-VPSS绑定。
//+------------------------------------------------------------------------------------------+
int L_VPSS_Init(void)
{
    HI_S32 s32Ret=HI_SUCCESS;

    do
    {
        memset(&stVPSSpara, 0, sizeof(VPSS_PARA_S));
        memcpy_s(&stVPSSpara, sizeof(VPSS_PARA_S), &stVPSSpara_default, sizeof(VPSS_PARA_S));
        /* 创建VPSS组 */
        s32Ret = HI_MPI_VPSS_CreateGrp(stVPSSpara.stVPSSGroup_para.VpssGrp,
                                   &(stVPSSpara.stVPSSGroup_para.stVpssGrpAttr));
        if(s32Ret != HI_SUCCESS){LOGE("[MPP-VPSS-ERROR]L_VPSS_Init:HI_MPI_VPSS_CreateGrp failed with %#x!\n", s32Ret);break;}

        /* 设置通道1属性并创建VPSS通道 */
        s32Ret = HI_MPI_VPSS_SetChnAttr(stVPSSpara.stVPSSGroup_para.VpssGrp,
                                      stVPSSpara.stVPSSChn1_para.VpssChn,
                                    &(stVPSSpara.stVPSSChn1_para.stVpssChnAttr));
        if(s32Ret != HI_SUCCESS){LOGE("[MPP-VPSS-ERROR]L_VPSS_Init:HI_MPI_VPSS_SetChnAttr[1] failed with %#x\n", s32Ret);break;}

        /* 设置通道2属性并创建VPSS通道 */
        s32Ret = HI_MPI_VPSS_SetChnAttr(stVPSSpara.stVPSSGroup_para.VpssGrp,
                                      stVPSSpara.stVPSSChn2_para.VpssChn,
                                    &(stVPSSpara.stVPSSChn2_para.stVpssChnAttr));
        if(s32Ret != HI_SUCCESS){LOGE("[MPP-VPSS-ERROR]L_VPSS_Init:HI_MPI_VPSS_SetChnAttr[2] failed with %#x\n", s32Ret);break;}

        /* 使能通道1 */
        s32Ret = HI_MPI_VPSS_EnableChn(stVPSSpara.stVPSSGroup_para.VpssGrp, stVPSSpara.stVPSSChn1_para.VpssChn);
        if(s32Ret != HI_SUCCESS){LOGE("[MPP-VPSS-ERROR]L_VPSS_Init:HI_MPI_VPSS_EnableChn[1] failed with %#x\n", s32Ret);break;}

        /* 使能通道2 */
        s32Ret = HI_MPI_VPSS_EnableChn(stVPSSpara.stVPSSGroup_para.VpssGrp, stVPSSpara.stVPSSChn2_para.VpssChn);
        if(s32Ret != HI_SUCCESS){LOGE("[MPP-VPSS-ERROR]L_VPSS_Init:HI_MPI_VPSS_EnableChn[2] failed with %#x\n", s32Ret);break;}

        /* 启动VPSS GROUP */
        s32Ret = HI_MPI_VPSS_StartGrp(stVPSSpara.stVPSSGroup_para.VpssGrp);
        if(s32Ret != HI_SUCCESS){LOGE("[MPP-VPSS-ERROR]L_VPSS_Init:HI_MPI_VPSS_CreateGrp failed with %#x!\n", s32Ret);break;}

        /* VI-VPSS绑定 */
        s32Ret = L_VIbindVPSS(0, 0, stVPSSpara.stVPSSGroup_para.VpssGrp);
        if(s32Ret != 0)break;

        return 0;
    }while(0);

    L_VPSS_DeInit();
    return -1;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：L_VIbindVPSS
//|  功能描述：进行VI-VPSS通道绑定。
//|  参数说明：无
//|  返回值说明：成功返回0
//|  备注：
//+------------------------------------------------------------------------------------------+
int L_VIbindVPSS(VI_PIPE ViPipe, VI_CHN ViChn, VPSS_GRP VpssGrp)
{
    HI_S32 s32Ret = HI_SUCCESS;
    MPP_CHN_S stSrcChn, stDestChn;
    stSrcChn.enModId  = HI_ID_VI;
    stSrcChn.s32DevId = ViPipe;
    stSrcChn.s32ChnId = ViChn;
    //----------------------------------------
    //VPSS作为数据接收者时，是以设备(GROUP)为接收者，
    //接收其他模块发来的数据，用户将通道号置为0。
    //——《参考》P62
    //----------------------------------------
    stDestChn.enModId  = HI_ID_VPSS;
    stDestChn.s32DevId = VpssGrp;
    stDestChn.s32ChnId = 0;

    s32Ret = HI_MPI_SYS_Bind(&stSrcChn, &stDestChn);
    if(s32Ret != HI_SUCCESS)
    {
        LOGE("[MPP-VPSS-ERROR]L_VIbindVPSS:VI bind VPSS failed with %#x!\n", s32Ret);
        L_VPSS_DeInit();
        return -1;
    }
    return 0;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：L_VIunbindVPSS
//|  功能描述：进行VI-VPSS通道解绑定。
//|  参数说明：无
//|  返回值说明：无
//|  备注：
//+------------------------------------------------------------------------------------------+
void L_VIunbindVPSS(VI_PIPE ViPipe, VI_CHN ViChn, VPSS_GRP VpssGrp)
{
    MPP_CHN_S stSrcChn, stDestChn;
    stSrcChn.enModId  = HI_ID_VI;
    stSrcChn.s32DevId = ViPipe;
    stSrcChn.s32ChnId = ViChn;
    //----------------------------------------
    //VPSS作为数据接收者时，是以设备(GROUP)为接收者，
    //接收其他模块发来的数据，用户将通道号置为0。
    //——《参考》P62
    //----------------------------------------
    stDestChn.enModId  = HI_ID_VPSS;
    stDestChn.s32DevId = VpssGrp;
    stDestChn.s32ChnId = 0;

    HI_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：L_VPSS_DeInit
//|  功能描述：VPSS去初始化。
//|  参数说明：无
//|  返回值说明：无
//|  备注：
//+------------------------------------------------------------------------------------------+
void L_VPSS_DeInit(void)
{
    //----------------------------------------
    //VPSS去初始化只需要很简单的四步：
    //开始之前确保没有后级模块连接在这个VPSS上。
    //第一步：解绑VPSS和前级数据来源之间的连接。
    //第二步：停止GROUP。
    //第三步：通道去使能。
    //第四步：组去使能。
    //----------------------------------------
    L_VIunbindVPSS(0, 0, stVPSSpara.stVPSSGroup_para.VpssGrp);
    HI_MPI_VPSS_StopGrp(stVPSSpara.stVPSSGroup_para.VpssGrp);
    HI_MPI_VPSS_DisableChn(stVPSSpara.stVPSSGroup_para.VpssGrp,stVPSSpara.stVPSSChn1_para.VpssChn);
    HI_MPI_VPSS_DisableChn(stVPSSpara.stVPSSGroup_para.VpssGrp,stVPSSpara.stVPSSChn2_para.VpssChn);
    HI_MPI_VPSS_DestroyGrp(stVPSSpara.stVPSSGroup_para.VpssGrp);
}
